package com.qf.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.dynamic.datasource.toolkit.DynamicDataSourceContextHolder;
import com.qf.constatns.OrderConstants;
import com.qf.constatns.RabbitMQConstatns;
import com.qf.entity.OrderDetailEntity;
import com.qf.entity.OrderEntity;
import com.qf.exception.StockMsg;
import com.qf.exception.vo.StockException;
import com.qf.feign.api.AddressService;
import com.qf.feign.api.CarService;
import com.qf.feign.api.StockServer;
import com.qf.interceptor.DynamicDataSourceInterceptor;
import com.qf.service.OrderDetailService;
import com.qf.utils.ExecutorUtils;
import com.qf.utils.OrderUtils;
import com.qf.vo.Address;
import com.qf.vo.Car;
import com.qf.vo.OrderParam;
import com.qf.vo.StockParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ThreadPoolExecutor;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;

import com.qf.mapper.OrderMapper;
import com.qf.service.OrderService;
import org.springframework.transaction.annotation.Transactional;


@Service("orderService")
@Slf4j
public class OrderServiceImpl extends ServiceImpl<OrderMapper, OrderEntity> implements OrderService {

    @Autowired
    private CarService carService;

    @Autowired
    private AddressService addressService;

    @Autowired
    private OrderDetailService orderDetailService;

    @Autowired
    private OrderUtils orderUtils;

    @Autowired
    private DynamicDataSourceInterceptor dataSourceInter;

    @Autowired
    private StockServer stockServer;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    @Transactional
    public String createOrder(OrderParam orderParam, Integer uid) throws ExecutionException, InterruptedException {

        // 从当前线程的ThreadLocak中获取数据表的编号
        Integer tabIndex = dataSourceInter.getTabIndex();

        // 获取已线程池
        ThreadPoolExecutor pool = ExecutorUtils.getExcutorsPool();

        // 1.查询用户地址
        CompletableFuture<Address> addRessFuture = CompletableFuture.supplyAsync(() -> {
            // 根据地址id查询地址的信息
            Address address = addressService.getAddressByUid(orderParam.getAddressId());
            return address;
        }, pool);

        // 2、查询用户购物车
        CompletableFuture<Map<String, Object>> carFuture = CompletableFuture.supplyAsync(() -> {
            // 获取feign返回的Map(JSON)
            Map<String, Object> carMap = null;
            if (!StringUtils.isEmpty(orderParam.getGid())) {
                List<String> gidList = Arrays.asList(orderParam.getGid().split(","));
                carMap = carService.getCarListByUidAndGid(uid, gidList);
            } else {
                carMap = carService.getCarListByUid(uid);
            }

            // 把JOSN转成Map
            List<Car> carList = null;
            BigDecimal totalPrice = BigDecimal.valueOf(Long.valueOf(carMap.get("totalPrice").toString()));
            List<Map<String, Object>> list = (List<Map<String, Object>>) carMap.get("carList");
            carList = JSON.parseArray(JSON.toJSONString(list), Car.class); // 先把list转成JSON字符串

            // 再封装成一个Map
            Map<String, Object> carObjectMap = new HashMap<>();
            carObjectMap.put("totalPrice", totalPrice);
            carObjectMap.put("carList", carList);
            return carObjectMap;
        }, pool);

        // 3.组合地址和购车的任务
        CompletableFuture<Void> addressAndCarFuture = CompletableFuture.allOf(addRessFuture, carFuture);
        Void aVoid = addressAndCarFuture.get(); // 阻塞，等待前面两个任务完成

        // 4.扣减库存
        CompletableFuture<String> orderFuture = CompletableFuture.supplyAsync(() -> {
            try {
                Map<String, Object> map = carFuture.get();
                List<Car> carList = (List<Car>) map.get("carList");

                List<StockParam> stockParamsList = new ArrayList<>();
                for (Car car : carList) {
                    StockParam stockParam = new StockParam(car.getGid(), car.getSum(), 1);
                    stockParamsList.add(stockParam);
                }
                return stockServer.lockGoodsStock(stockParamsList);
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }
            return false;
        }, pool)
                .thenApplyAsync((stockFlag) -> {
                    if (stockFlag) {
                        // 创建订单Id
                        String oid = orderUtils.createOrderId(uid);

                        try {
                            // 先获取之前计算好的数据
                            Address address = addRessFuture.get();
                            Map<String, Object> map = carFuture.get();
                            List<Car> carList = (List<Car>) map.get("carList");
                            BigDecimal totalPrice = (BigDecimal) map.get("totalPrice");

                            // 3.创建订单
                            OrderEntity order = new OrderEntity();
                            order.setOid(oid);
                            order.setUid(uid);
                            order.setAddress(address.getAddress());
                            order.setName(address.getName());
                            order.setPhone(address.getPhone());
                            order.setCreateTime(new Date());
                            order.setStatus(1);
                            order.setTotalPrice(totalPrice);
                            order.setPayType(2);
                            order.setSubject(carList.get(0).getGoods().getGname());
                            order.setBody(carList.get(0).getGoods().getGdesc());

                            // 5、保存订单
                            baseMapper.insertOrder(order, tabIndex); // t_order

                            // 6.创建订单详情
                            List<OrderDetailEntity> orderDetailEntities = new ArrayList<>();

                            for (Car car : carList) {
                                // 封装对象
                                OrderDetailEntity od = new OrderDetailEntity();
                                od.setGid(car.getGid());
                                od.setGdesc(car.getGoods().getGdesc()); // 历史数据
                                od.setGname(car.getGoods().getGname());
                                od.setGpng(car.getGoods().getGpng());
                                od.setGprice(car.getGoods().getGprice());
                                od.setOid(oid);
                                od.setSum(car.getSum());
                                od.setSubTotal(car.getSubTotal());

                                // 添加集合中
                                orderDetailEntities.add(od);
                            }

                            // 7.插入订单详情
                            orderDetailService.saveBatchOrderDetail(orderDetailEntities, tabIndex);


                            // 发送消息给MQ，开始计算超时时间
                            rabbitTemplate.convertAndSend(RabbitMQConstatns.ORDER_EXCHANGE, "order.insert", order);

                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } catch (ExecutionException e) {
                            e.printStackTrace();
                        }
                        return oid;
                    } else {
                        System.out.println("扣减库存失败。。");
                        return null;
                    }
                }, pool);

        String oid = orderFuture.get();
        System.out.println("最后的oid:" + oid);
        if (StringUtils.isEmpty(oid)) {
            throw new StockException(StockMsg.UNLOCK_STOCK_ERROR);
        }
        return oid;
    }

    @Override
    public OrderEntity getOrderById(String oid, Integer tabIndex) {
        return baseMapper.getOrderById(oid, tabIndex);
    }

    private Integer getLastUserIdByOid(String oid) {
        String lastUserId = oid.substring(13, 13 + 4);
        return Integer.parseInt(lastUserId);
    }


    @Override
    public void updateOrderStatus(String oid, Integer status) {

        // 1.根据Oid获取用户id后四位
        Integer lastUid = getLastUserIdByOid(oid);

        // 1.设置数据源
        Integer dbIndex = (lastUid % OrderConstants.ORDER_DB_SIZE) + 1;
        String dataSourceKey = OrderConstants.ORDER_DB_PRE + dbIndex;
        DynamicDataSourceContextHolder.push(dataSourceKey);

        // 2.计算表的编号
        Integer tabIndex = (lastUid / OrderConstants.ORDER_DB_SIZE % OrderConstants.ORDER_TABLE_SIZE) + 1;


        baseMapper.updateOrderStatus(oid, status, tabIndex);
    }

    @Override
    public OrderEntity getOrderById2(String oid) {
        // 1.根据Oid获取用户id后四位
        Integer lastUid = getLastUserIdByOid(oid);

        // 1.设置数据源
        Integer dbIndex = (lastUid % OrderConstants.ORDER_DB_SIZE) + 1;
        String dataSourceKey = OrderConstants.ORDER_DB_PRE + dbIndex;
        DynamicDataSourceContextHolder.push(dataSourceKey);

        // 2.计算表的编号
        Integer tabIndex = (lastUid / OrderConstants.ORDER_DB_SIZE % OrderConstants.ORDER_TABLE_SIZE) + 1;

        return baseMapper.getOrderById(oid,tabIndex);
    }

    @Override
    public OrderEntity getOrderInfoById(String oid) {
        // 1.根据Oid获取用户id后四位
        Integer lastUid = getLastUserIdByOid(oid);

        // 1.设置数据源
        Integer dbIndex = (lastUid % OrderConstants.ORDER_DB_SIZE) + 1;
        String dataSourceKey = OrderConstants.ORDER_DB_PRE + dbIndex;
        DynamicDataSourceContextHolder.push(dataSourceKey);

        // 2.计算表的编号
        Integer tabIndex = (lastUid / OrderConstants.ORDER_DB_SIZE % OrderConstants.ORDER_TABLE_SIZE) + 1;

        return baseMapper.getOrderInfoById(oid,tabIndex);
    }



   /* @Override
    @Transactional
    public String createOrder(OrderParam orderParam, Integer uid) {

        log.debug("【OrderServiceImpl】当前线程id:{}", Thread.currentThread().getId());
        Map<String, Object> carMap = null;

        // 1.判断用户是否勾选支付
        if (!StringUtils.isEmpty(orderParam.getGid())) {
            // 勾选支付
            List<String> gidList = Arrays.asList(orderParam.getGid().split(","));
            carMap = carService.getCarListByUidAndGid(uid, gidList);
        } else {
            // 没有勾选
            carMap = carService.getCarListByUid(uid);
        }

        // 2.获取购物车和总价
        List<Car> carList = null;
        BigDecimal totalPrice = BigDecimal.valueOf(Long.valueOf(carMap.get("totalPrice").toString()));
        List<Map<String, Object>> list = (List<Map<String, Object>>) carMap.get("carList");
        carList = JSON.parseArray(JSON.toJSONString(list), Car.class); // 先把list转成JSON字符串

        log.debug("sum:{},gname:{}", carList.get(0).getSum(), carList.get(0).getGoods().getGname());


        List<StockParam> stockParamsList = new ArrayList<>();
        for (Car car : carList) {
            // 仓库id可以根据收货地址就近选择
            StockParam stockParam = new StockParam(car.getGid(), car.getSum(), 1);
            stockParamsList.add(stockParam);
        }

        // 扣减库存(有可能会出现扣减库存失败的情况)
        Boolean stockLock = stockServer.lockGoodsStock(stockParamsList);
        if (!stockLock) {
            // 扣减库存失败，用户购买的商品中库存不足
            throw new StockException(StockMsg.UNLOCK_STOCK_ERROR);
        }

        // 根据地址id查询地址的信息
        Address address = addressService.getAddressByUid(orderParam.getAddressId());

        String oid = orderUtils.createOrderId(uid);

        // 3.创建订单
        OrderEntity order = new OrderEntity();
        order.setOid(oid);
        order.setUid(uid);
        order.setAddress(address.getAddress());
        order.setName(address.getName());
        order.setPhone(address.getPhone());
        order.setCreateTime(new Date());
        order.setStatus(1);
        order.setTotalPrice(totalPrice);
        order.setPayType(2);

        log.debug("order:{}", order);
        log.debug("carList:{}", carList);

        // 从当前线程的ThreadLocak中获取数据表的编号
        Integer tabIndex = dataSourceInter.getTabIndex();

        // 5、保存订单
        baseMapper.insertOrder(order, tabIndex); // t_order

        // 6.创建订单详情
        List<OrderDetailEntity> orderDetailEntities = new ArrayList<>();

        for (Car car : carList) {
            // 封装对象
            OrderDetailEntity od = new OrderDetailEntity();
            od.setGid(car.getGid());
            od.setGdesc(car.getGoods().getGdesc()); // 历史数据
            od.setGname(car.getGoods().getGname());
            od.setGpng(car.getGoods().getGpng());
            od.setGprice(car.getGoods().getGprice());
            od.setOid(oid);
            od.setSum(car.getSum());
            od.setSubTotal(car.getSubTotal());

            // 添加集合中
            orderDetailEntities.add(od);
        }

        // 7.插入订单详情
        orderDetailService.saveBatchOrderDetail(orderDetailEntities, tabIndex);

        return oid;
    }*/
}